package com.example.bean.lifecycle;

import org.junit.Assert;
import org.junit.Test;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessor;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * @author linfeng
 * @date 2022/4/14 15:17
 */
public class InstantiationAwareBeanPostProcessorTestTwo {

    public static class SimpleInstantiationAwareBeanPostProcessor implements InstantiationAwareBeanPostProcessor{

        @Override
        public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
            return null;
        }

        // 这个方法在通过构造函数或工厂方法实例化 bean 之后，但在 Spring 属性填充（来自显式属性或自动装配）发生之前执行。
        // 这是在给定 bean 实例上执行自定义字段注入的理想回调，就在 Spring 的自动装配开始之前。
        @Override
        public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
            if(bean instanceof SimpleTestBean){
                System.out.println("InstantiationAwareBeanPostProcessorTestTwo#postProcessAfterInstantiation()方法被调用，beanName:" + beanName);

                // 这个方法返回false的话，Spring不会再为该bean进行自动装配
                // 并且后续也不会为该bean执行其它的InstantiationAwareBeanPostProcessor
                SimpleTestBean simpleTestBean = (SimpleTestBean) bean;
                simpleTestBean.setName("张三");
                return false;
            }
            return true;
        }
    }

    public static class SimpleTestBean implements BeanNameAware, BeanFactoryAware, ApplicationContextAware, BeanClassLoaderAware, InitializingBean {
        private String name;

        private String beanName;
        private BeanFactory beanFactory;
        private ApplicationContext applicationContext;
        private ClassLoader beanClassLoader;

        @Autowired
        private SimpleDependency simpleDependency;

        public SimpleTestBean() {
            System.out.println("SimpleTestBean无参构造方法被调用");
        }

        public SimpleTestBean(String name) {
            this.name = name;
            System.out.println("SimpleTestBean带参构造方法被调用，参数：" + name);
        }

        @Override
        public void setBeanClassLoader(ClassLoader classLoader) {
            System.out.println("SimpleTestBean#setBeanClassLoader()方法被调用");
            this.beanClassLoader = classLoader;
        }

        @Override
        public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
            System.out.println("SimpleTestBean#setBeanFactory()方法被调用");
            this.beanFactory = beanFactory;
        }

        @Override
        public void setBeanName(String name) {
            System.out.println("SimpleTestBean#setBeanName()方法被调用");
            this.beanName = name;
        }

        @Override
        public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
            System.out.println("SimpleTestBean#setApplicationContext()方法被调用");
            this.applicationContext = applicationContext;
        }

        @Override
        public void afterPropertiesSet() throws Exception {
            System.out.println("afterPropertiesSet()方法被调用");
        }

        // setter and getter

        public void setName(String name) {
            this.name = name;
        }

        public String getName() {
            return name;
        }

        public String getBeanName() {
            return beanName;
        }

        public BeanFactory getBeanFactory() {
            return beanFactory;
        }

        public ApplicationContext getApplicationContext() {
            return applicationContext;
        }

        public ClassLoader getBeanClassLoader() {
            return beanClassLoader;
        }

        public SimpleDependency getSimpleDependency() {
            return simpleDependency;
        }
    }

    public static class SimpleDependency{
        private String name;

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }
    }

    @Configuration
    public static class AppConfig {

        @Bean
        public SimpleTestBean simpleTestBean(){
            SimpleTestBean simpleTestBean = new SimpleTestBean();
            simpleTestBean.setName("李四");
            return simpleTestBean;
        }

        @Bean
        public SimpleInstantiationAwareBeanPostProcessor simpleInstantiationAwareBeanPostProcessor(){
            return new SimpleInstantiationAwareBeanPostProcessor();
        }

        @Bean
        public SimpleDependency simpleDependency(){
            SimpleDependency simpleDependency = new SimpleDependency();
            simpleDependency.setName("简单依赖项1");
            return simpleDependency;
        }
    }

    @Test
    public void test(){
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
        SimpleTestBean bean = context.getBean(SimpleTestBean.class);

        Assert.assertEquals("张三", bean.getName());

        Assert.assertNotNull(bean.getBeanName());
        Assert.assertNotNull(bean.getBeanFactory());
        Assert.assertNotNull(bean.getBeanClassLoader());
        Assert.assertNotNull(bean.getApplicationContext());
        Assert.assertNull(bean.getSimpleDependency()); // 由于SimpleInstantiationAwareBeanPostProcessor#postProcessAfterInstantiation
                                                      // 返回了false，因此属性依赖不会被自动注入
    }
}
